﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace WcfContrib.Client
{
    /// <summary>
    /// Represents the status of a client channel asynchronous operation.
    /// </summary>
    public class ChannelInvokeAsyncResult : IAsyncResult
    {
        IAsyncResult innerResult = null;
        bool HasInnerResult { get; set; }

        private object result;
        /// <summary>
        /// Gets the result.
        /// </summary>
        /// <value>The result.</value>
        public object Result
        {
            get { return result; }
            private set { result = value; }
        }

        /// <summary>
        /// Gets a value indicating whether an error has occured.
        /// </summary>
        /// <value><c>true</c> if an error has occured; otherwise, <c>false</c>.</value>
        public bool HasError
        {
            get { return exceptionStage.HasValue; }
        }

        private Exception exception;
        /// <summary>
        /// Gets the exception.
        /// </summary>
        /// <value>The exception.</value>
        public Exception Exception
        {
            get { return exception; }
            private set { exception = value; }
        }

        private AsyncInvokeStage? exceptionStage;
        /// <summary>
        /// Gets the stage in which the exception occured.
        /// </summary>
        /// <value>The exception stage.</value>
        public AsyncInvokeStage? ExceptionStage
        {
            get { return exceptionStage; }
            private set { exceptionStage = value; }
        }

        private object asyncState;
        /// <summary>
        /// Gets a user-defined object that qualifies or contains information about an asynchronous operation.
        /// </summary>
        /// <value></value>
        /// <returns>
        /// A user-defined object that qualifies or contains information about an asynchronous operation.
        /// </returns>
        public object AsyncState
        {
            get { return asyncState; }
            private set { asyncState = value; }
        }

        /// <summary>
        /// Gets a <see cref="T:System.Threading.WaitHandle"/> that is used to wait for an asynchronous operation to complete.
        /// </summary>
        /// <value></value>
        /// <returns>
        /// A <see cref="T:System.Threading.WaitHandle"/> that is used to wait for an asynchronous operation to complete.
        /// </returns>
        public WaitHandle AsyncWaitHandle
        {
            get { return (HasInnerResult) ? innerResult.AsyncWaitHandle : null; }
        }

        /// <summary>
        /// Gets a value that indicates whether the asynchronous operation completed synchronously.
        /// </summary>
        /// <value></value>
        /// <returns>true if the asynchronous operation completed synchronously; otherwise, false.
        /// </returns>
        public bool CompletedSynchronously
        {
            get { return (HasInnerResult) ? innerResult.CompletedSynchronously : false; }
        }

        /// <summary>
        /// Gets a value that indicates whether the asynchronous operation has completed.
        /// </summary>
        /// <value></value>
        /// <returns>true if the operation is complete; otherwise, false.
        /// </returns>
        public bool IsCompleted
        {
            get { return (HasInnerResult) ? innerResult.IsCompleted : false; }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ChannelInvokeAsyncResult"/> class.
        /// </summary>
        /// <param name="innerResult">The wrapped async result.</param>
        /// <param name="exception">The exception.</param>
        /// <param name="exceptionStage">The exception stage.</param>
        /// <param name="asyncState">The async state object.</param>
        public ChannelInvokeAsyncResult(IAsyncResult innerResult, Exception exception, AsyncInvokeStage exceptionStage, object asyncState)
        {
            this.innerResult = innerResult;
            HasInnerResult = innerResult != null;
            this.exception = exception;
            this.exceptionStage = exceptionStage;
            this.asyncState = asyncState;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ChannelInvokeAsyncResult"/> class.
        /// </summary>
        /// <param name="result">The result.</param>
        /// <param name="asyncState">The async state object.</param>
        public ChannelInvokeAsyncResult(object result, object asyncState)
        {
            this.result = result;
            this.asyncState = asyncState;
        }
    }
}
